home *** CD-ROM | disk | FTP | other *** search
/ The World's Largest Collection of Windows Software / The World's Largest Collection of Windows Software - Disc 2.iso / games / _b2 / winmaze4 / plot3d.cpp < prev    next >
C/C++ Source or Header  |  1994-05-19  |  48KB  |  1,097 lines

  1. #include <owl\owlpch.h>
  2. #include <owl\applicat.h>
  3. #include <owl\framewin.h>
  4. #include <owl\dc.h>
  5. #include <string.h>
  6. #include <math.h>
  7. #include <stdlib.h>
  8. #include "plot3d.h"
  9.  
  10. #ifndef TRUE
  11. #define TRUE -1
  12. #endif
  13. #ifndef FALSE
  14. #define FALSE 0
  15. #endif
  16.  
  17. plot3d::plot3d(TFrameWindow *ptr)
  18.   {
  19.     window_ptr=ptr;
  20.     TClientDC *dc=new TClientDC(*window_ptr);
  21.     long num_colors_free=1L
  22.      << (long(dc->GetDeviceCaps(PLANES))*long(dc->GetDeviceCaps(BITSPIXEL)));
  23.     num_colors_free-=long(dc->GetDeviceCaps(NUMCOLORS));
  24.     delete dc;
  25.     if (num_colors_free < 16L)
  26.       {
  27.         use_palette=FALSE;
  28.         num_colors=256;
  29.       }
  30.     else
  31.       {
  32.         use_palette=TRUE;
  33.         if (num_colors_free > 256L)
  34.           num_colors=256;
  35.         else
  36.           num_colors=int(num_colors_free);
  37.       }
  38.     corner_allocated=FALSE;
  39.     plot_prepared=FALSE;
  40.     prepare_plot_state='B';
  41.     plot_state='B';
  42.     int color_num;
  43.     for (int color_index=0; color_index < (num_colors-1); color_index++)
  44.       {
  45.         color_num=int((255L*long(color_index))/long(num_colors-2));
  46.         palette_entry[color_index].peRed=(BYTE) color_num;
  47.         palette_entry[color_index].peGreen=(BYTE) color_num;
  48.         palette_entry[color_index].peBlue=(BYTE) color_num;
  49.         palette_entry[color_index].peFlags=(BYTE) PC_NOCOLLAPSE;
  50.       }
  51.     palette_entry[color_index].peRed=(BYTE) 255;
  52.     palette_entry[color_index].peGreen=(BYTE) 0;
  53.     palette_entry[color_index].peBlue=(BYTE) 0;
  54.     palette_entry[color_index].peFlags=(BYTE) PC_NOCOLLAPSE;
  55.     palette=new TPalette(&palette_entry[0],num_colors);
  56.     lightest_gray=int((240L*long(num_colors-2))/254L);
  57.     darkest_gray=(19*(num_colors-2))/254;
  58.   }
  59.  
  60. plot3d::~plot3d()
  61.   {
  62.     delete palette;
  63.     if (corner_allocated)
  64.       {
  65.         for (x_division_num=(num_x_divisions-1); x_division_num >= 0;
  66.          x_division_num--)
  67.           delete[] corner[x_division_num--];
  68.         delete[] corner;
  69.       }
  70.   }
  71.  
  72. char plot3d::prepare_plot(
  73.   double (*f)(double,double),
  74.   double x_min,
  75.   double x_max,
  76.   double y_min,
  77.   double y_max,
  78.   int    (*external_to_plot)(double,double),
  79.   int    (*red)(double,double),
  80.   int    x_division_count,
  81.   int    y_division_count,
  82.   double rotation_in_degrees,
  83.   double tilt_in_degrees,
  84.   double light_x,
  85.   double light_y,
  86.   double light_z)
  87. //     This function returns 'S' if it is successful in preparing the plot for
  88. //  generation.  It returns 'C' if it should be called again (because more work
  89. //  must be done).  Otherwise, it returns 'F' indicating a failure.  Its
  90. //  parameters are as follow:
  91. //
  92. //           f -- z=f(x,y), the function to be plotted.  Before the plot is
  93. //      tilted or rotated, the z-axis runs from the bottom to the top of the
  94. //      display, the y-axis runs from the left to the right of the display,
  95. //      and the x-axis runs out of the display.
  96. //
  97. //           x_min -- the minimum value of x to be plotted.
  98. //
  99. //           x_max -- the maximum value of x to be plotted.
  100. //
  101. //           y_min -- the minimum value of y to be plotted.
  102. //
  103. //           y_max -- the maximum value of y to be plotted.
  104. //
  105. //           external_to_plot -- a function that returns TRUE if and only if a
  106. //      point should be omitted from the plot.
  107. //
  108. //           red -- a function that returns TRUE if and only if a point should
  109. //      be flagged for highlighting.  A point should be so flagged only if it
  110. //      can be seen in the final plot.
  111. //
  112. //           x_division_count -- the number of x divisions to be used in
  113. //      constructing the plot.  At least two must be specified.
  114. //
  115. //           y_division_count -- the number of y divisions to be used in
  116. //      constructing the plot.  At least two must be specified.
  117. //
  118. //           rotation_in_degrees -- rotation (degrees) about an axis parallel to
  119. //      the z-axis and through the center of the surface.
  120. //
  121. //           tilt_in_degrees -- tilt (degrees) about an axis through the center
  122. //      of the surface and parallel to a line from the lower left hand corner of
  123. //      the display to the lower right hand corner of the display.  The plot is
  124. //      tilted after it is rotated.
  125. //
  126. //           (light_x,light_y,light_z) -- a vector pointing to the light source
  127. //      (at infinity).  The light source remains fixed while the plot is rotated
  128. //      or tilted.
  129.     {
  130.       char result;
  131.  
  132.       result='C';
  133.       switch (prepare_plot_state)
  134.         {
  135.            case 'B': // begin
  136.              plot_prepared=FALSE;
  137.              if (corner_allocated)
  138.                {
  139.                  for (x_division_num=(num_x_divisions-1); x_division_num >= 0;
  140.                   x_division_num--)
  141.                    delete[] corner[x_division_num--];
  142.                  delete[] corner;
  143.                  corner_allocated=FALSE;
  144.                }
  145.              num_x_divisions=x_division_count;
  146.              num_y_divisions=y_division_count;
  147.              corner_allocated
  148.               =((corner=new corner_rec_ptr [num_x_divisions]) != NULL);
  149.              for (x_division_num=0;
  150.               ((corner_allocated) && (x_division_num < num_x_divisions));
  151.               x_division_num++)
  152.                if (corner_allocated=
  153.                 ((corner [x_division_num]=new corner_rec [num_y_divisions])
  154.                 != NULL))
  155.                  for (y_division_num=0; y_division_num < num_y_divisions;
  156.                   y_division_num++)
  157.                    {
  158.                      corner[x_division_num][y_division_num].base_z
  159.                       =(unsigned char) '\0';
  160.                      corner[x_division_num][y_division_num].color
  161.                       =(unsigned char) '\0';
  162.                      corner[x_division_num][y_division_num].x=(float) 0.0;
  163.                      corner[x_division_num][y_division_num].y=(float) 0.0;
  164.                      corner[x_division_num][y_division_num].z=(float) 0.0;
  165.                      corner[x_division_num][y_division_num].x_division_index=0;
  166.                      corner[x_division_num][y_division_num].y_division_index=0;
  167.                    };
  168.              if (corner_allocated)
  169.                {
  170.                  rotation=rotation_in_degrees;
  171.                  tilt=tilt_in_degrees;
  172.                  light.x=light_x;
  173.                  light.y=light_y;
  174.                  light.z=light_z;
  175.                  prepare_plot_state='E';
  176.                  TClientDC *dc=new TClientDC(*window_ptr);
  177.                  dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
  178.                  dc->TextOut(0,0,"Evaluating...");
  179.                  delete dc;
  180.                  x_division_num=0;
  181.                  y_division_num=0;
  182.                }
  183.              else
  184.                {
  185.                  x_division_num--;
  186.                  while (x_division_num >= 0)
  187.                    delete[] corner[x_division_num--];
  188.                  delete[] corner;
  189.                  prepare_plot_state='F';
  190.                  result='F';
  191.                }
  192.              break;
  193.            case 'E': // evaluate and transform
  194.              evaluate_and_transform(f,x_min,x_max,y_min,y_max,
  195.               num_x_divisions,num_y_divisions,rotation,tilt,
  196.               external_to_plot,red);
  197.               // Compute the vertices, etc. of the quadrilaterals composing the
  198.               // plot.
  199.              if (x_division_num >= num_x_divisions)
  200.                {
  201.                  prepare_plot_state='H';
  202.                  TClientDC *dc=new TClientDC(*window_ptr);
  203.                  dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
  204.                  dc->TextOut(0,0,"Shading...");
  205.                  delete dc;
  206.                  x_division_num=num_x_divisions-1;
  207.                  y_division_num=num_y_divisions-1;
  208.                }
  209.              break;
  210.            case 'H': // shade
  211.              shade();
  212.                // Compute the shade of gray for each quadrilateral composing the
  213.                // plot.
  214.              if (x_division_num < 0)
  215.                {
  216.                  if (((y_corner_max-y_corner_min) > (z_corner_max-z_corner_min))
  217.                  ||  (z_corner_max != z_corner_min))
  218.                    {
  219.                      if ((y_corner_max-y_corner_min)
  220.                       > (z_corner_max-z_corner_min))
  221.                        x_eye=1.1*(y_corner_max-y_corner_min)+x_corner_max;
  222.                      else
  223.                        x_eye=1.1*(z_corner_max-z_corner_min)+x_corner_max;
  224.                      prepare_plot_state='A';
  225.                      TClientDC *dc=new TClientDC(*window_ptr);
  226.                      dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
  227.                      dc->TextOut(0,0,"Adjusting perspective...");
  228.                      delete dc;
  229.                      x_division_num=0;
  230.                      y_division_num=0;
  231.                    }
  232.                  else
  233.                    {
  234.                      stacked_bound_head=new sort_stack_rec;
  235.                      stacked_bound_head->bound.lower_x=0;
  236.                      stacked_bound_head->bound.lower_y=0;
  237.                      stacked_bound_head->bound.upper_x=(num_x_divisions-1);
  238.                      stacked_bound_head->bound.upper_y=(num_y_divisions-1);
  239.                      stacked_bound_head->previous=NULL;
  240.                      prepare_plot_state='S';
  241.                      TClientDC *dc=new TClientDC(*window_ptr);
  242.                      dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
  243.                      dc->TextOut(0,0,"Sorting...");
  244.                      delete dc;
  245.                    }
  246.                }
  247.              break;
  248.            case 'A': // adjust perspective
  249.              adjust_perspective();
  250.                // Force parallel lines running away from the viewer to converge
  251.                // at the horizon.
  252.              if (x_division_num >= num_x_divisions)
  253.                {
  254.                  stacked_bound_head=new sort_stack_rec;
  255.                  stacked_bound_head->bound.lower_x=0;
  256.                  stacked_bound_head->bound.lower_y=0;
  257.                  stacked_bound_head->bound.upper_x=(num_x_divisions-1);
  258.                  stacked_bound_head->bound.upper_y=(num_y_divisions-1);
  259.                  stacked_bound_head->previous=NULL;
  260.                  prepare_plot_state='S';
  261.                  TClientDC *dc=new TClientDC(*window_ptr);
  262.                  dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
  263.                  dc->TextOut(0,0,"Sorting...");
  264.                  delete dc;
  265.                }
  266.              break;
  267.            case 'S': // sort back to front
  268.              sort_back_to_front();
  269.              if (stacked_bound_head == NULL)
  270.                {
  271.                  prepare_plot_state='D';
  272.                  TClientDC *dc=new TClientDC(*window_ptr);
  273.                  dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
  274.                  delete dc;
  275.                }
  276.              break;
  277.            case 'F': // failed
  278.              result='F';
  279.              break;
  280.            default: // done
  281.              plot_prepared=TRUE;
  282.              result='S';
  283.              break;
  284.         }
  285.       return result;
  286.     }
  287.  
  288. void plot3d::evaluate_and_transform(
  289.   double (*f)(double,double),
  290.   double x_min,
  291.   double x_max,
  292.   double y_min,
  293.   double y_max,
  294.   int    num_x_divisions,
  295.   int    num_y_divisions,
  296.   double rotation,
  297.   double tilt,
  298.   int    (*external_to_plot)(double,double),
  299.   int    (*red)(double,double))
  300. // Compute the vertices, etc. for each quadrilateral composing the plot.
  301.     {
  302.       double tem_x;
  303.       double tem_y;
  304.       double tem_z;
  305.       double x_rotated;
  306.       double z;
  307.  
  308.       if ((x_division_num == 0) && (y_division_num == 0))
  309.         {
  310.           double degrees_per_radian=45.0/atan(1.0);
  311.           radians=tilt/degrees_per_radian;
  312.           cos_tilt=cos(radians);
  313.           sin_tilt=sin(radians);
  314.           radians=rotation/degrees_per_radian;
  315.           cos_rotation=cos(radians);
  316.           sin_rotation=sin(radians);
  317.           z=f(x_min,y_min);
  318.           x_rotated=x_min*cos_rotation+y_min*sin_rotation;
  319.           y_corner_min=-x_min*sin_rotation+y_min*cos_rotation;
  320.           z_corner_min=-x_rotated*sin_tilt+z*cos_tilt;
  321.           y_corner_max=y_corner_min;
  322.           z_corner_max=z_corner_min;
  323.           x_corner_max=x_rotated*cos_tilt+z*sin_tilt;
  324.           x_delta=(double) (num_x_divisions-1);
  325.           x_delta=(x_max-x_min)/x_delta;
  326.           y_delta=(double) (num_y_divisions-1);
  327.           y_delta=(y_max-y_min)/y_delta;
  328.           x=x_min;
  329.           y=y_min;
  330.         }
  331.       int finished=FALSE;
  332.       DWORD start_time=GetTickCount();
  333.       DWORD current_time;
  334.       while ((! finished) && (x_division_num < num_x_divisions))
  335.         {
  336.           z=f(x,y);
  337.           if (external_to_plot(x,y))
  338.             corner[x_division_num][y_division_num].base_z=(unsigned char) 3;
  339.           else
  340.             if (red(x,y))
  341.               corner[x_division_num][y_division_num].base_z=(unsigned char) 2;
  342.             else
  343.               corner[x_division_num][y_division_num].base_z=(unsigned char) 1;
  344.           corner[x_division_num][y_division_num].x_division_index
  345.            =x_division_num;
  346.           corner[x_division_num][y_division_num].y_division_index
  347.            =y_division_num;
  348.           x_rotated=x*cos_rotation+y*sin_rotation;
  349.           tem_y=(-x*sin_rotation+y*cos_rotation);
  350.           corner[x_division_num][y_division_num].y=(float) tem_y;
  351.           tem_x=(x_rotated*cos_tilt+z*sin_tilt);
  352.           corner[x_division_num][y_division_num].x=(float) tem_x;
  353.           tem_z=(-x_rotated*sin_tilt+z*cos_tilt);
  354.           corner[x_division_num][y_division_num].z=(float) tem_z;
  355.           if (tem_x > x_corner_max)
  356.             x_corner_max=tem_x;
  357.           if (tem_y < y_corner_min)
  358.             y_corner_min=tem_y;
  359.           if (tem_y > y_corner_max)
  360.             y_corner_max=tem_y;
  361.           if (tem_z < z_corner_min)
  362.             z_corner_min=tem_z;
  363.           if (tem_z > z_corner_max)
  364.             z_corner_max=tem_z;
  365.           y+=y_delta;
  366.           y_division_num++;
  367.           if (y_division_num >= num_y_divisions)
  368.             {
  369.               y_division_num=0;
  370.               y=y_min;
  371.               x+=x_delta;
  372.               x_division_num++;
  373.             }
  374.           current_time=GetTickCount();
  375.           finished=((current_time < start_time)
  376.            || ((current_time-start_time) > 100));
  377.         }
  378.       if (x_division_num >= num_x_divisions)
  379.         {
  380.           double magnitude=light.x*light.x+light.y*light.y+light.z*light.z;
  381.           magnitude=sqrt(magnitude);
  382.           light.x=light.x/magnitude;
  383.           light.y=light.y/magnitude;
  384.           light.z=light.z/magnitude;
  385.         }
  386.       return;
  387.     }
  388.  
  389. void plot3d::shade()
  390. // Compute the shade of gray for each quadrilateral composing the plot.
  391.     {
  392.       int        color_num;
  393.       double     magnitude;
  394.       vertex_rec normal;
  395.       vertex_rec vertex [4];
  396.  
  397.       if ((x_division_num == (num_x_divisions-1))
  398.       &&  (y_division_num == (num_y_divisions-1)))
  399.         {
  400.           color_min=(unsigned char) (num_colors-1);
  401.           color_max=(unsigned char) '\0';
  402.         }
  403.       int finished=FALSE;
  404.       DWORD start_time=GetTickCount();
  405.       DWORD current_time;
  406.       while ((! finished) && (x_division_num >= 0))
  407.         {
  408.           vertex[0].x=(double) (corner[x_division_num][y_division_num].x);
  409.           vertex[0].y=(double) (corner[x_division_num][y_division_num].y);
  410.           vertex[0].z=(double) (corner[x_division_num][y_division_num].z);
  411.           if (x_division_num < (num_x_divisions-1))
  412.             if (y_division_num < (num_y_divisions-1))
  413.               {
  414.                 x_division_num++;
  415.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  416.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  417.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  418.                 y_division_num++;
  419.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  420.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  421.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  422.                 x_division_num--;
  423.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  424.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  425.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  426.                 y_division_num--;
  427.               }
  428.             else
  429.               {
  430.                 y_division_num--;
  431.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  432.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  433.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  434.                 x_division_num++;
  435.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  436.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  437.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  438.                 y_division_num++;
  439.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  440.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  441.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  442.                 x_division_num--;
  443.               }
  444.           else
  445.             if (y_division_num < (num_y_divisions-1))
  446.               {
  447.                 y_division_num++;
  448.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  449.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  450.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  451.                 x_division_num--;
  452.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  453.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  454.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  455.                 y_division_num--;
  456.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  457.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  458.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  459.                 x_division_num++;
  460.               }
  461.             else
  462.               {
  463.                 x_division_num--;
  464.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  465.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  466.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  467.                 y_division_num--;
  468.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  469.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  470.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  471.                 x_division_num++;
  472.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  473.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  474.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  475.                 y_division_num++;
  476.               }
  477.           // Compute the normal to a quadrilateral by averaging the
  478.           // normals to each vertex of the quadrilateral.
  479.           normal.x
  480.            =(vertex[1].y-vertex[0].y)*(vertex[3].z-vertex[0].z)
  481.            -(vertex[3].y-vertex[0].y)*(vertex[1].z-vertex[0].z)
  482.            +(vertex[2].y-vertex[1].y)*(vertex[0].z-vertex[1].z)
  483.            -(vertex[0].y-vertex[1].y)*(vertex[2].z-vertex[1].z)
  484.            +(vertex[3].y-vertex[2].y)*(vertex[1].z-vertex[2].z)
  485.            -(vertex[1].y-vertex[2].y)*(vertex[3].z-vertex[2].z)
  486.            +(vertex[0].y-vertex[3].y)*(vertex[2].z-vertex[3].z)
  487.            -(vertex[2].y-vertex[3].y)*(vertex[0].z-vertex[3].z);
  488.           normal.y
  489.            =(vertex[3].x-vertex[0].x)*(vertex[1].z-vertex[0].z)
  490.            -(vertex[1].x-vertex[0].x)*(vertex[3].z-vertex[0].z)
  491.            +(vertex[0].x-vertex[1].x)*(vertex[2].z-vertex[1].z)
  492.            -(vertex[2].x-vertex[1].x)*(vertex[0].z-vertex[1].z)
  493.            +(vertex[1].x-vertex[2].x)*(vertex[3].z-vertex[2].z)
  494.            -(vertex[3].x-vertex[2].x)*(vertex[1].z-vertex[2].z)
  495.            +(vertex[2].x-vertex[3].x)*(vertex[0].z-vertex[3].z)
  496.            -(vertex[0].x-vertex[3].x)*(vertex[2].z-vertex[3].z);
  497.           normal.z
  498.            =(vertex[1].x-vertex[0].x)*(vertex[3].y-vertex[0].y)
  499.            -(vertex[3].x-vertex[0].x)*(vertex[1].y-vertex[0].y)
  500.            +(vertex[2].x-vertex[1].x)*(vertex[0].y-vertex[1].y)
  501.            -(vertex[0].x-vertex[1].x)*(vertex[2].y-vertex[1].y)
  502.            +(vertex[3].x-vertex[2].x)*(vertex[1].y-vertex[2].y)
  503.            -(vertex[1].x-vertex[2].x)*(vertex[3].y-vertex[2].y)
  504.            +(vertex[0].x-vertex[3].x)*(vertex[2].y-vertex[3].y)
  505.            -(vertex[2].x-vertex[3].x)*(vertex[0].y-vertex[3].y);
  506.           magnitude
  507.            =sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z);
  508.           if (magnitude == 0.0)
  509.             {
  510.               color_min=(unsigned char) '\0';
  511.               corner[x_division_num][y_division_num].color=(unsigned char) '\0';
  512.             }
  513.           else
  514.             {
  515.               color_num=int((double(num_colors)/2.0)
  516.                *(1.0+(light.x*normal.x+light.y*normal.y
  517.                +light.z*normal.z)/magnitude)); // shadows not absolute
  518.               if (color_num >= num_colors)
  519.                 color_num=num_colors-1;
  520.               corner[x_division_num][y_division_num].color
  521.                =(unsigned char) color_num;
  522.               if ((corner[x_division_num][y_division_num].color) < color_min)
  523.                 color_min=(corner[x_division_num][y_division_num].color);
  524.               if ((corner[x_division_num][y_division_num].color) > color_max)
  525.                 color_max=(corner[x_division_num][y_division_num].color);
  526.             }
  527.           y_division_num--;
  528.           if (y_division_num < 0)
  529.             {
  530.               y_division_num=num_y_divisions-1;
  531.               x_division_num--;
  532.             }
  533.           current_time=GetTickCount();
  534.           finished=((current_time < start_time)
  535.            || ((current_time-start_time) > 100));
  536.         }
  537.       return;
  538.     }
  539.  
  540. void plot3d::adjust_perspective()
  541. // Make parallel lines running away from the viewer appear to converge at the
  542. // horizon.  
  543.     {
  544.       double     tem;
  545.       vertex_rec vertex [4];
  546.  
  547.       if ((x_division_num == 0) && (y_division_num == 0))
  548.         {
  549.           y_center=(y_corner_max+y_corner_min)/2.0;
  550.           z_center=(z_corner_max+z_corner_min)/2.0;
  551.         }
  552.       int finished=FALSE;
  553.       DWORD start_time=GetTickCount();
  554.       DWORD current_time;
  555.       while ((! finished) && (x_division_num < num_x_divisions))
  556.         {
  557.           vertex[0].x=(double) (corner[x_division_num][y_division_num].x);
  558.           vertex[0].y=(double) (corner[x_division_num][y_division_num].y);
  559.           vertex[0].z=(double) (corner[x_division_num][y_division_num].z);
  560.           if (x_division_num < (num_x_divisions-1))
  561.             if (y_division_num < (num_y_divisions-1))
  562.               {
  563.                 x_division_num++;
  564.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  565.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  566.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  567.                 y_division_num++;
  568.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  569.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  570.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  571.                 x_division_num--;
  572.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  573.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  574.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  575.                 y_division_num--;
  576.               }
  577.             else
  578.               {
  579.                 y_division_num--;
  580.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  581.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  582.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  583.                 x_division_num++;
  584.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  585.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  586.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  587.                 y_division_num++;
  588.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  589.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  590.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  591.                 x_division_num--;
  592.               }
  593.           else
  594.             if (y_division_num < (num_y_divisions-1))
  595.               {
  596.                 y_division_num++;
  597.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  598.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  599.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  600.                 x_division_num--;
  601.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  602.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  603.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  604.                 y_division_num--;
  605.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  606.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  607.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  608.                 x_division_num++;
  609.               }
  610.             else
  611.               {
  612.                 x_division_num--;
  613.                 vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
  614.                 vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
  615.                 vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
  616.                 y_division_num--;
  617.                 vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
  618.                 vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
  619.                 vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
  620.                 x_division_num++;
  621.                 vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
  622.                 vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
  623.                 vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
  624.                 y_division_num++;
  625.               }
  626.           tem=y_center
  627.            +(vertex[0].y-y_center)*(x_eye-x_corner_max)
  628.            /(x_eye-vertex[0].x);
  629.           corner[x_division_num][y_division_num].y=(float) tem;
  630.           tem=z_center
  631.            +(vertex[0].z-z_center)*(x_eye-x_corner_max)
  632.            /(x_eye-vertex[0].x);
  633.           corner[x_division_num][y_division_num].z=(float) tem;
  634.           tem=(vertex[0].x+vertex[1].x+vertex[2].x+vertex[3].x)/4.0;
  635.           corner[x_division_num][y_division_num].x=(float) tem;
  636.           y_division_num++;
  637.           if (y_division_num >= num_y_divisions)
  638.             {
  639.               y_division_num=0;
  640.               x_division_num++;
  641.             }
  642.           current_time=GetTickCount();
  643.           finished=((current_time < start_time)
  644.            || ((current_time-start_time) > 100));
  645.         }
  646.       return;
  647.     }
  648.  
  649. void plot3d::rearrange(
  650.   int lower_bound_x,
  651.   int lower_bound_y,
  652.   int upper_bound_x,
  653.   int upper_bound_y,
  654.   int *j_x,
  655.   int *j_y)
  656.     {
  657.       int       down_x;
  658.       int       down_y;
  659.       int       finished;
  660.       int       up_x;
  661.       int       up_y;
  662.       float     x1;
  663.       int       x_division_index1;
  664.       int       y_division_index1;
  665.  
  666.       x1=corner[lower_bound_x][lower_bound_y].x;
  667.       x_division_index1=corner[lower_bound_x][lower_bound_y].x_division_index;
  668.       y_division_index1=corner[lower_bound_x][lower_bound_y].y_division_index;
  669.       *j_x=lower_bound_x;
  670.       *j_y=lower_bound_y;
  671.       up_x=upper_bound_x;
  672.       up_y=upper_bound_y;
  673.       down_x=lower_bound_x;
  674.       down_y=lower_bound_y;
  675.       do
  676.         {
  677.           finished=FALSE;
  678.           while (! finished)
  679.             {
  680.               if ((up_x < down_x)
  681.               ||  ((up_x == down_x) && (up_y <= down_y)))
  682.                 finished=TRUE;
  683.               else
  684.                 if (corner[up_x][up_y].x < x1)
  685.                   finished=TRUE;
  686.                 else
  687.                   {
  688.                     if (--up_y < 0)
  689.                       {
  690.                         up_y=num_y_divisions-1;
  691.                         up_x--;
  692.                       }
  693.                   }
  694.             }
  695.           *j_x=up_x;
  696.           *j_y=up_y;
  697.           if ((up_x != down_x) || (up_y != down_y))
  698.             {
  699.               corner[down_x][down_y].x=corner[up_x][up_y].x;
  700.               corner[down_x][down_y].x_division_index
  701.                =corner[up_x][up_y].x_division_index;
  702.               corner[down_x][down_y].y_division_index
  703.                =corner[up_x][up_y].y_division_index;
  704.               finished=FALSE;
  705.               while (! finished)
  706.                 {
  707.                   if ((down_x > up_x)
  708.                   ||  ((down_x == up_x) && (down_y >= up_y)))
  709.                     finished=TRUE;
  710.                   else
  711.                     if (corner[down_x][down_y].x > x1)
  712.                       finished=TRUE;
  713.                     else
  714.                       {
  715.                         if (++down_y >= num_y_divisions)
  716.                           {
  717.                             down_y=0;
  718.                             down_x++;
  719.                           }
  720.                       }
  721.                 }
  722.               *j_x=down_x;
  723.               *j_y=down_y;
  724.               if ((down_x != up_x) || (down_y != up_y))
  725.                 {
  726.                   corner[up_x][up_y].x=corner[down_x][down_y].x;
  727.                   corner[up_x][up_y].x_division_index
  728.                    =corner[down_x][down_y].x_division_index;
  729.                   corner[up_x][up_y].y_division_index
  730.                    =corner[down_x][down_y].y_division_index;
  731.                 }
  732.             }
  733.         }
  734.       while ((down_x != up_x) || (down_y != up_y));
  735.       corner[*j_x][*j_y].x=x1;
  736.       corner[*j_x][*j_y].x_division_index=x_division_index1;
  737.       corner[*j_x][*j_y].y_division_index=y_division_index1;
  738.       return;
  739.     }
  740.  
  741. void plot3d::sort_back_to_front()
  742. //      The painter's algorithm is used; items farther from the viewer are drawn
  743. // earlier.
  744.     {
  745.       int            i_x;
  746.       int            i_y;
  747.       int            j_x;
  748.       int            j_y;
  749.       sort_bound_rec stacked_bound;
  750.       sort_stack_rec *stacked_bound_ptr;
  751.  
  752.       int finished=FALSE;
  753.       DWORD start_time=GetTickCount();
  754.       DWORD current_time;
  755.       while ((! finished) && (stacked_bound_head != NULL))
  756.         {
  757.           stacked_bound.lower_x=stacked_bound_head->bound.lower_x;
  758.           stacked_bound.lower_y=stacked_bound_head->bound.lower_y;
  759.           stacked_bound.upper_x=stacked_bound_head->bound.upper_x;
  760.           stacked_bound.upper_y=stacked_bound_head->bound.upper_y;
  761.           stacked_bound_ptr=stacked_bound_head;
  762.           stacked_bound_head=stacked_bound_head->previous;
  763.           delete stacked_bound_ptr;
  764.           while ((stacked_bound.upper_x > stacked_bound.lower_x)
  765.           ||     ((stacked_bound.upper_x == stacked_bound.lower_x)
  766.                && (stacked_bound.upper_y > stacked_bound.lower_y)))
  767.             {
  768.               rearrange(stacked_bound.lower_x,stacked_bound.lower_y,
  769.                stacked_bound.upper_x,stacked_bound.upper_y,&j_x,&j_y);
  770.               if (long(num_y_divisions)*long(j_x-stacked_bound.lower_x)
  771.                +(j_y-stacked_bound.lower_y)
  772.                >  long(num_y_divisions)*long(stacked_bound.upper_x-j_x)
  773.                +(stacked_bound.upper_y-j_y))
  774.                 {
  775.                   i_x=stacked_bound.upper_x;
  776.                   i_y=stacked_bound.upper_y;
  777.                   stacked_bound.upper_y=j_y-1;
  778.                   stacked_bound.upper_x=j_x;
  779.                   if (stacked_bound.upper_y < 0)
  780.                     {
  781.                       stacked_bound.upper_y=num_y_divisions-1;
  782.                       (stacked_bound.upper_x)--;
  783.                     }
  784.                   stacked_bound_ptr=new sort_stack_rec;
  785.                   stacked_bound_ptr->bound.lower_x=stacked_bound.lower_x;
  786.                   stacked_bound_ptr->bound.lower_y=stacked_bound.lower_y;
  787.                   stacked_bound_ptr->bound.upper_x=stacked_bound.upper_x;
  788.                   stacked_bound_ptr->bound.upper_y=stacked_bound.upper_y;
  789.                   stacked_bound_ptr->previous=stacked_bound_head;
  790.                   stacked_bound_head=stacked_bound_ptr;
  791.                   stacked_bound.lower_y=j_y+1;
  792.                   stacked_bound.lower_x=j_x;
  793.                   if (stacked_bound.lower_y >= num_y_divisions)
  794.                     {
  795.                       stacked_bound.lower_y=0;
  796.                       (stacked_bound.lower_x)++;
  797.                     }
  798.                   stacked_bound.upper_x=i_x;
  799.                   stacked_bound.upper_y=i_y;
  800.                 }
  801.               else
  802.                 {
  803.                   i_x=stacked_bound.lower_x;
  804.                   i_y=stacked_bound.lower_y;
  805.                   stacked_bound.lower_y=j_y+1;
  806.                   stacked_bound.lower_x=j_x;
  807.                   if (stacked_bound.lower_y >= num_y_divisions)
  808.                     {
  809.                       stacked_bound.lower_y=0;
  810.                       (stacked_bound.lower_x)++;
  811.                     }
  812.                   stacked_bound_ptr=new sort_stack_rec;
  813.                   stacked_bound_ptr->bound.lower_x=stacked_bound.lower_x;
  814.                   stacked_bound_ptr->bound.lower_y=stacked_bound.lower_y;
  815.                   stacked_bound_ptr->bound.upper_x=stacked_bound.upper_x;
  816.                   stacked_bound_ptr->bound.upper_y=stacked_bound.upper_y;
  817.                   stacked_bound_ptr->previous=stacked_bound_head;
  818.                   stacked_bound_head=stacked_bound_ptr;
  819.                   stacked_bound.lower_x=i_x;
  820.                   stacked_bound.lower_y=i_y;
  821.                   stacked_bound.upper_y=j_y-1;
  822.                   stacked_bound.upper_x=j_x;
  823.                   if (stacked_bound.upper_y < 0)
  824.                     {
  825.                       stacked_bound.upper_y=num_y_divisions-1;
  826.                       (stacked_bound.upper_x)--;
  827.                     }
  828.                 }
  829.             }
  830.           current_time=GetTickCount();
  831.           finished=((current_time < start_time)
  832.            || ((current_time-start_time) > 100));
  833.         }
  834.       return;
  835.     }
  836.  
  837. char plot3d::plot(
  838.   TRect   ®ion_to_paint,
  839.   int     show_red,
  840.   int     only_plot_red,
  841.   double  bias)
  842. //     This function returns 'S' if it is successful in generating the 3D plot.
  843. //  It returns 'C' if it should be called again (because more work must be done
  844. //  on the plot).  Otherwise, it returns 'F' indicating a failure.  Its
  845. //  parameters are as follow:
  846. //
  847. //           region_to_paint -- only points in this rectangle will be plotted.
  848. //
  849. //           show_red -- highlight quadrilaterals having each vertex flagged
  850. //      to be highlighted.  
  851. //
  852. //           only_plot_red -- only plot the quadrilaterals having each vertex
  853. //      flagged to be highlighted.
  854. //
  855. //           bias -- a positive number used to adjust the contrast.
  856. //
  857. // "prepare_plot" must be called before "plot", after which "plot" may be called
  858. // as many times as desired.
  859.     {
  860.       TPoint     box [4];
  861.       int        box_num;
  862.       int        color_num;
  863.       DWORD      current_time;
  864.       int        finished;
  865.       double     fraction;
  866.       int        outside_maze;
  867.       int        red_showing;
  868.       char       result;
  869.       DWORD      start_time;
  870.       vertex_rec vertex [4];
  871.       int        x_division_index;
  872.       int        y_division_index;
  873.       double     y_out_max;
  874.  
  875.       if (plot_prepared)
  876.         {
  877.           result='C';
  878.           TClientDC *dc=new TClientDC(*window_ptr);
  879.           TRect ClipBox;
  880.           if (dc->GetClipBox(ClipBox) != NULLREGION)
  881.             switch (plot_state)
  882.               {
  883.                 case 'B': // begin
  884.                   aspect_ratio
  885.                    =(double(dc->GetDeviceCaps(VERTSIZE))
  886.                    /double(dc->GetDeviceCaps(HORZSIZE)))
  887.                    /(double(dc->GetDeviceCaps(VERTRES))
  888.                    /double(dc->GetDeviceCaps(HORZRES)));
  889.                   y_out_max=double(window_ptr->GetClientRect().Width()-1);
  890.                   z_out_max=double(window_ptr->GetClientRect().Height()-1);
  891.                   if (aspect_ratio*z_out_max*(y_corner_max-y_corner_min)
  892.                    > y_out_max*(z_corner_max-z_corner_min))
  893.                     {
  894.                       pixels_per_unit
  895.                        =y_out_max/(aspect_ratio*(y_corner_max-y_corner_min));
  896.                       y_offset=0.0;
  897.                       z_offset
  898.                        =-(z_out_max-pixels_per_unit*(z_corner_max-z_corner_min))
  899.                        /2.0;
  900.                     }
  901.                   else
  902.                     if (aspect_ratio*z_out_max*(y_corner_max-y_corner_min)
  903.                      < y_out_max*(z_corner_max-z_corner_min))
  904.                       {
  905.                         pixels_per_unit=z_out_max/(z_corner_max-z_corner_min);
  906.                         y_offset=(y_out_max
  907.                          -aspect_ratio*pixels_per_unit
  908.                          *(y_corner_max-y_corner_min))/2.0;
  909.                         z_offset=0.0;
  910.                       }
  911.                     else
  912.                       {
  913.                         pixels_per_unit=1.0;
  914.                         y_offset=y_out_max/2.0;
  915.                         z_offset=-z_out_max/2.0;
  916.                       }
  917.                   x_division_num=y_division_num=0;
  918.                   plot_state='P';
  919.                   break;
  920.                 case 'P': // plot
  921.                   finished=FALSE;
  922.                   start_time=GetTickCount();
  923.                   while ((! finished) && (x_division_num < num_x_divisions))
  924.                     {
  925.                       x_division_index
  926.                        =corner[x_division_num][y_division_num].x_division_index;
  927.                       if (x_division_index < (num_x_divisions-1))
  928.                         {
  929.                           y_division_index=corner[x_division_num][
  930.                            y_division_num].y_division_index;
  931.                           if (y_division_index < (num_y_divisions-1))
  932.                             {
  933.                               color_num=int(corner[x_division_index][
  934.                                y_division_index].color);
  935.                               // Adjust contrast.
  936.                               fraction=((double) (color_num-int(color_min)))
  937.                                /((double) (color_max-color_min));
  938.                               if (fraction > 0.0)
  939.                                 {
  940.                                   fraction=exp(bias*log(fraction));
  941.                                   color_num=(int)
  942.                                    (((double) (lightest_gray-darkest_gray))
  943.                                    *fraction
  944.                                    +((double) darkest_gray));
  945.                                 }
  946.                               else
  947.                                 color_num=darkest_gray;
  948.                               vertex[0].y=(double)
  949.                                (corner[x_division_index][y_division_index].y);
  950.                               vertex[0].z=(double) 
  951.                                (corner[x_division_index][y_division_index].z);
  952.                               red_showing=(corner[x_division_index][
  953.                                y_division_index].base_z == (unsigned char) 2);
  954.                               outside_maze=(corner[x_division_index][
  955.                                y_division_index].base_z == (unsigned char) 3);
  956.                               x_division_index++;
  957.                               vertex[1].y=(double)
  958.                                (corner[x_division_index][y_division_index].y);
  959.                               vertex[1].z=(double) 
  960.                                (corner[x_division_index][y_division_index].z);
  961.                               if (red_showing)
  962.                                 red_showing=(corner[x_division_index][
  963.                                  y_division_index].base_z == (unsigned char) 2);
  964.                               if (outside_maze)
  965.                                 outside_maze=(corner[x_division_index][
  966.                                  y_division_index].base_z == (unsigned char) 3);
  967.                               y_division_index++;
  968.                               vertex[2].y=(double)
  969.                                (corner[x_division_index][y_division_index].y);
  970.                               vertex[2].z=(double)
  971.                                (corner[x_division_index][y_division_index].z);
  972.                               if (red_showing)
  973.                                 red_showing=(corner[x_division_index][
  974.                                  y_division_index].base_z == (unsigned char) 2);
  975.                               if (outside_maze)
  976.                                 outside_maze=(corner[x_division_index][
  977.                                  y_division_index].base_z == (unsigned char) 3);
  978.                               x_division_index--;
  979.                               vertex[3].y=(double)
  980.                                (corner[x_division_index][y_division_index].y);
  981.                               vertex[3].z=(double)
  982.                                (corner[x_division_index][y_division_index].z);
  983.                               if (red_showing)
  984.                                 red_showing=(corner[x_division_index][
  985.                                  y_division_index].base_z == (unsigned char) 2);
  986.                               if (outside_maze)
  987.                                 outside_maze=(corner[x_division_index][
  988.                                  y_division_index].base_z == (unsigned char) 3);
  989.                               if (((! only_plot_red) || (red_showing))
  990.                               &&  (! outside_maze))
  991.                                // Plot each point in a quadrilateral.
  992.                                 {
  993.                                   for (box_num=0; box_num < 4; box_num++)
  994.                                     {
  995.                                       box[box_num].x=(int) (y_offset
  996.                                        +pixels_per_unit*aspect_ratio
  997.                                        *(vertex[box_num].y-y_corner_min));
  998.                                       box[box_num].y
  999.                                        =(int) (z_offset+z_out_max
  1000.                                        -pixels_per_unit
  1001.                                        *(vertex[box_num].z-z_corner_min));
  1002.                                     }
  1003.                                   dc->SelectClipRgn(region_to_paint);
  1004.                                   if (use_palette)
  1005.                                     {
  1006.                                       dc->SelectObject(*palette);
  1007.                                       dc->RealizePalette();
  1008.                                       if ((show_red) && (red_showing))
  1009.                                         {
  1010.                                           TColor palColor(num_colors-1);
  1011.                                           TBrush brush(palColor);
  1012.                                           dc->SelectObject(brush);
  1013.                                           TPen pen(palColor,1,PS_NULL);
  1014.                                           dc->SelectObject(pen);
  1015.                                           dc->Polygon(&box[0],4);
  1016.                                           dc->RestorePen();
  1017.                                           dc->RestoreBrush();
  1018.                                         }
  1019.                                       else
  1020.                                         {
  1021.                                           TColor palColor(color_num);
  1022.                                           TBrush brush(palColor);
  1023.                                           dc->SelectObject(brush);
  1024.                                           TPen pen(palColor,1,PS_NULL);
  1025.                                           dc->SelectObject(pen);
  1026.                                           dc->Polygon(&box[0],4);
  1027.                                           dc->RestorePen();
  1028.                                           dc->RestoreBrush();
  1029.                                         }
  1030.                                       dc->RestorePalette();
  1031.                                     }
  1032.                                   else
  1033.                                     {
  1034.                                       if ((show_red) && (red_showing))
  1035.                                         {
  1036.                                           TBrush brush(RGB(255,0,0));
  1037.                                           dc->SelectObject(brush);
  1038.                                           TPen pen(RGB(255,0,0),1,PS_NULL);
  1039.                                           dc->SelectObject(pen);
  1040.                                           dc->Polygon(&box[0],4);
  1041.                                           dc->RestorePen();
  1042.                                           dc->RestoreBrush();
  1043.                                         }
  1044.                                       else
  1045.                                         {
  1046.                                           TBrush brush(RGB(color_num,color_num,
  1047.                                            color_num));
  1048.                                           dc->SelectObject(brush);
  1049.                                           TPen pen(RGB(color_num,color_num,
  1050.                                            color_num),1,PS_NULL);
  1051.                                           dc->SelectObject(pen);
  1052.                                           dc->Polygon(&box[0],4);
  1053.                                           dc->RestorePen();
  1054.                                           dc->RestoreBrush();
  1055.                                         }
  1056.                                     }
  1057.                                 }
  1058.                             }
  1059.                         }
  1060.                       if (++y_division_num >= num_y_divisions)
  1061.                         {
  1062.                           y_division_num=0;
  1063.                           x_division_num++;
  1064.                         }
  1065.                       current_time=GetTickCount();
  1066.                       finished=((current_time < start_time)
  1067.                       || ((current_time-start_time) > 100));
  1068.                     }
  1069.                   if (x_division_num >= num_x_divisions)
  1070.                     plot_state='S';
  1071.                   break;
  1072.                 case 'F': // failed
  1073.                   result='F';
  1074.                   break;
  1075.                 default:  // done
  1076.                   result='S';
  1077.                   break;
  1078.               }
  1079.           delete dc;
  1080.         }
  1081.       else 
  1082.         {
  1083.           result='F'; // attempt to plot before prepared
  1084.           window_ptr->MessageBox("Attempt to plot before prepared!",
  1085.            window_ptr->GetApplication()->GetName(),
  1086.            MB_OK | MB_ICONEXCLAMATION);
  1087.         }
  1088.       return result;
  1089.     }
  1090.  
  1091.  
  1092. void plot3d::restart_plot()
  1093.   {
  1094.     if (plot_prepared)
  1095.       plot_state='B';
  1096.   }
  1097.